
#include <cstdio>
#include <BFile>
#include "member_BFile.h"

using namespace BWE;

#define member					(*(member_BFile*)_ptr)
#define member_allocate()		_ptr = new member_BFile
#define member_release()		delete (member_BFile*)_ptr

#ifdef _LINUX_
#include "member_BFile.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

inline void file_perror(const char* operation, const BString& fileName)
{
	char buffer[256];
	sprintf(buffer, "%s : %s", operation, fileName.cstr());
	perror(buffer);
}

bool BFile::Find(const BString& fileName)
{
	int ret = ::access(fileName.cstr(),F_OK);
	if(ret == 0)
		return true;
	return false;
}
bool BFile::Create(const BString& fileName)
{
	int fd = ::creat(fileName.cstr(), S_IRWXU | S_IRWXG | S_IRWXO);
	if(fd == -1)
	{
		file_perror("create file : %s", fileName.cstr());
		return false;
	}
	::close(fd);
	return true;
}
bool BFile::Remove(const BString& fileName)
{
	int result = ::remove(fileName.cstr());
	if(result == 0)
		return true;
	return false;
}
bool BFile::Rename(const BString& oldName, const BString& newName)
{
	int result = ::rename(oldName.cstr(), newName.cstr());
	if(result == 0)
		return true;
	return false;
}

BFile::BFile()
{
	member_allocate();
}
BFile::BFile(const BString& fileName)
{
	member_allocate();
	member.fileName = fileName;
	open();
}
BFile::~BFile()
{
	if(member.handle)
		::close(member.handle);
	member_release();
}

const BString& BFile::fileName() const
{
	return member.fileName;
}
const BString& BFile::filePath() const
{
	return member.filePath;
}

time_t BFile::modifyTime() const
{
	if(member.handle == 0)
		return 0;
	
	class stat fs;
	::fstat(member.handle, &fs);
	return fs.st_mtime;
}

time_t BFile::changeTime() const
{
	if(member.handle == 0)
		return 0;
	
	class stat fs;
	::fstat(member.handle, &fs);
	return fs.st_ctime;
}

time_t BFile::accessTime() const
{
	if(member.handle == 0)
		return 0;
	
	class stat fs;
	::fstat(member.handle, &fs);
	return fs.st_atime;
}

bool BFile::isOpened() const
{
	return member.handle != 0;
}

bool BFile::isBegin() const
{
	if(member.handle == 0)
		return false;
	return this->offset() == 0;
}
bool BFile::isEnd() const
{
	if(member.handle == 0)
		return false;
	return this->offset() == this->size();
}
int BFile::size() const
{
	if(member.handle == 0)
		return -1;
		
	class stat fs;
	::fstat(member.handle, &fs);
	return fs.st_size;
}

bool BFile::open(FileMode mode)
{
	if(!close())
		return false;
	
	if(member.fileName.empty())
		return false;

    member.mode = mode;

	int flags = 0;
	switch(mode)
	{
	case Mode_Read:			flags = O_RDONLY;	break;
	case Mode_Write:		flags = O_WRONLY;	break;
	case Mode_Append:		flags = O_APPEND;	break;
	case Mode_ReadWrite:	flags = O_RDWR;		break;
	default:
		return false;
	}
	member.handle = ::open(member.fileName.cstr(), flags);
	if(member.handle == -1)
	{
		member.handle = 0;
		file_perror("create file", member.fileName);
		return false;
	}
	return true;
}
bool BFile::open(const BString& fileName, FileMode mode)
{
	member.fileName = fileName;
	return open(mode);
}
bool BFile::close()
{
	if(member.handle == 0)
		return false;

	if(::close(member.handle) == 0)
	{
		file_perror("close file", member.fileName);
	}
	member.handle = 0;
	member.fileName.clear();
	return true;
}
FileMode BFile::mode() const
{
    if(!member.fp)
        return Mode_None;
    return member.mode;
}

bool BFile::seek(int offset, Seek seek) const
{
	if(member.handle == 0)
		return false;
	int whence = 0;
	switch(whence)
	{
	case Seek_Begin:	whence = SEEK_SET;	break;
	case Seek_Current:	whence = SEEK_CUR;	break;
	case Seek_End:		whence = SEEK_END;	break;
	default:
		return false;
	}

	int ret = ::lseek(member.handle, offset, whence);
	if(ret == -1)
	{
		file_perror("lseek file", member.fileName);
		return false;
	}
	return true;
}
int BFile::offset() const
{
	if(member.handle == 0)
		return -1;
	int ret = ::lseek(member.handle, 0, SEEK_CUR);
	if(ret == -1)
	{
		file_perror("lseek file", member.fileName);
	}
	return ret;
}
int BFile::remain() const
{
	if(member.handle == 0)
		return -1;
	int pos = ::lseek(member.handle, 0, SEEK_CUR);
	if(pos == -1)
		file_perror("lseek file", member.fileName);
	return this->size() - pos;
}

bool BFile::flush()
{
	return false;
}

bool BFile::readAll(BByteArray& bytes) const
{
	if(member.handle == 0)
		return -1;
	
	int size = this->size();
	bytes.resize(size);
	return read(bytes.data(), size);
}

bool BFile::read(bool& value) const
{
	if(member.handle == 0)
		return false;
	return ::read(member.handle, &value, sizeof(bool));
}
bool BFile::read(char& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(char));
}
bool BFile::read(short& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(short));
}
bool BFile::read(int& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(int));
}

bool BFile::read(unsigned char& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(unsigned char));
}
bool BFile::read(unsigned short& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(unsigned short));
}
bool BFile::read(unsigned int& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(unsigned int));
}

bool BFile::read(float& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(float));
}
bool BFile::read(double& value) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, &value, sizeof(double));
}

bool BFile::read(void* buffer, int size) const
{
	if(member.handle == 0)
		return -1;
	return ::read(member.handle, buffer, size);
}
bool BFile::read(char* cstr, int size) const
{
	if(member.handle == 0)
		return -1;
	for(int i = 0; i < size; i++)
	{
		if(::read(member.handle, cstr + i, 1) == 0)
		{
			cstr[i] = 0;
			return i;
		}
		if(cstr[i] == 0)
			return i;
	}
	return 0;
}
bool BFile::read(BString& str) const
{
	if(member.handle == 0)
		return -1;
	str.clear();
	char chr;
	while(::read(member.handle, &chr, 1) > 0)
	{
		if(chr == 0)
			break;
		str.append(chr);
	}
	return str.size();
}

bool BFile::readLine(char* cstr, int maxSize) const
{
	if(member.handle == 0 || cstr == 0)
		return false;
	char chr;
	int pos = 0;
	while(::read(member.handle, &chr, 1) > 0)
	{
		if(chr == '\n')
			chr = 0;
		cstr[pos] = chr;
		if(chr == 0)
			break;
		pos++;
	}
	return pos > 0;
}
bool BFile::readLine(BString& str) const
{
	if(member.handle == 0)
		return -1;
	str.clear();
	char chr;
	while(::read(member.handle, &chr, 1) > 0)
	{
		if(chr == '\n')
			chr = 0;
		str.append(chr);
		if(chr == 0)
			break;
	}
	return str.size();
}


bool BFile::write(bool value)
{
	if(member.handle == 0)
		return false;
	return ::write(member.handle, &value, sizeof(bool));
}
bool BFile::write(char value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(short value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(int value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}

bool BFile::write(unsigned char value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(unsigned short value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(unsigned int value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}

bool BFile::write(float value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(double value)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, &value, sizeof(value));
}
bool BFile::write(const char* cstr)
{
	if(member.handle == 0)
		return -1;
	int len = ::strlen(cstr) + 1;
	return ::write(member.handle, cstr, len);
}
bool BFile::write(const BString& str)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, str.data(), str.size() + 1);
}
bool BFile::write(const void* buffer, int size)
{
	if(member.handle == 0)
		return -1;
	return ::write(member.handle, buffer, size);
}

bool BFile::writeLine(const char* cstr)
{
	if(member.fp)
		return std::fputs(cstr, member.fp) >= 0;
	return true;
}
bool BFile::writeLine(const BString& str)
{
	if(member.handle == 0)
		return -1;
	int count = ::write(member.handle, str.data(), str.size() + 1);
	::write(member.handle, "\n", 1);
	return count + 1;
}

#endif

#ifdef _WINDOWS_SYSTEM_

bool BFile::Exists(const BString& fileName)
{
	DWORD attrib = GetFileAttributes(fileName.cstr());
	if(attrib == INVALID_FILE_ATTRIBUTES)
		return false;
	return true;
}
bool BFile::Create(const BString& fileName)
{
	//::CreateFileA(
	return false;
}
bool BFile::Remove(const BString& fileName)
{
	int result = std::remove(fileName.cstr());
	if(result == 0)
		return true;
	return false;
}
bool BFile::Rename(const BString& oldName, const BString& newName)
{
	int result = std::rename(oldName.cstr(), newName.cstr());
	if(result == 0)
		return true;
	return false;
}

BFile::BFile()
{
	member_allocate();
}
BFile::BFile(const BString& fileName)
{
	member_allocate();
	member.fileName = fileName;
}
BFile::~BFile()
{
	close();
	member_release();
}

void BFile::setFileName(const BString& fileName)
{
	if (member.fileName != fileName)
	{
		member.fileName = fileName;
		close();
	}
}
const BString& BFile::fileName() const
{
	return member.fileName;
}

bool BFile::isOpened() const
{
	if(member.fp)
		return true;
	return false;
}

bool BFile::open(BFile::Mode mode)
{
	close();
	if(member.fileName.size())
	{
		const char* flags = 0;
		switch(mode)
		{
		case Mode_Read:			flags = "rb";	break;
		case Mode_Write:		flags = "wb";	break;
		case Mode_Append:		flags = "ab+";	break;
		case Mode_ReadWrite:	flags = "wb+";	break;
		default: break;
		}
		member.fp = ::fopen(member.fileName.cstr(), flags);
		if(member.fp)
		{
			member.mode = mode;
			::fseek(member.fp, 0, SEEK_END);
			int size = ::ftell(member.fp);
			member.size = ::ftell(member.fp);
			::fseek(member.fp, 0, SEEK_SET);
			return true;
		}
	}
	return false;
}
bool BFile::open(const BString& fileName, Mode mode)
{
	close();
	member.fileName = fileName;
	return open(mode);
}
bool BFile::close()
{
	if(member.fp)
	{
		if(std::fclose(member.fp) == 0)
		{
			member.fp = 0;
			member.size = 0;
			return true;
		}
	}
	return false;
}
bool BFile::flush()
{
	if(member.fp)
	{
		if(::fflush(member.fp) == 0)
			return true;
	}
	return false;
}

bool BFile::seek(int offset) const
{
	if(member.fp)
	{
		if(::fseek(member.fp, offset, SEEK_SET) == 0)
			return true;
	}
	return false;
}
bool BFile::wseek(int offset)
{
	if (!member.fp)
		return false;

	int size = member.size;
	if (offset > member.size)
	{
		int count = offset - member.size;
		if(count != fwrite(&count, 1, count, member.fp))
			return false;
		member.size += count;
	}
	else
	{
		if (fseek(member.fp, offset, SEEK_SET))
			return false;
	}
	return true;
}

int BFile::offset() const
{
	if (!member.fp)
		return -1;
	return ::ftell(member.fp);
}
int BFile::size() const
{
	return member.size;
}

bool BFile::read(void* data, int size) const
{
	if (!member.fp || size < 1)
		return false;
	if (size != fread(data, 1, size, member.fp))
		return false;
	return true;
}
bool BFile::write(const void* data, int size)
{
	if (!member.fp || !data || size < 1)
		return false;
	if (size != fwrite(data, 1, size, member.fp))
		return false;
	int offset = ftell(member.fp);
	if (offset > member.size)
		member.size = offset;
	return true;
}

bool BFile::readString(char* cstr, int maxSize)
{
	if (!cstr || maxSize <= 0)
		return false;
	char code = 0;
	for (int i = 0; i < maxSize; i++)
	{
		if (!read(code))
		{
			cstr[0] = 0;
			return false;
		}
		cstr[i] = code;
		if (code == 0)
		{
			return true;
		}
	}
	return false;
}
bool BFile::readString(BString& str)
{
	str.clear();
	char code = 0;
	while (read(code))
	{
		if (code == 0)
			return true;
		str.append(code);
	}
	return false;
}

bool BFile::writeString(const char* cstr, int len)
{
	if (len < 0)
		len = strlen(cstr);
	return write(cstr, len + 1);
}
bool BFile::writeString(const BString& str)
{
	return write(str.cstr(), str.size() + 1);
}


#endif
